package com.gitee.wsl.net.resource


import com.gitee.wsl.io.cache.CacheStrategy
import com.gitee.wsl.io.cache.DiskCacheStrategy
import com.gitee.wsl.ioDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.io.files.Path
import timber.log.Timber
import io.ktor.client.HttpClient
import io.ktor.client.plugins.HttpRequestRetry
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsBytes
import io.ktor.utils.io.InternalAPI

val DefaultHttpClient by lazy {
    HttpClient {
        followRedirects = true
        expectSuccess = true
        install(HttpTimeout){
            requestTimeoutMillis = 15_000
            connectTimeoutMillis = 15_000
        }
        install(HttpRequestRetry) {
            maxRetries = 2
            constantDelay(1000, 500)
        }
    }
}

@OptIn(InternalAPI::class)
internal val DefaultHttpRequest : suspend  (String) -> ByteArray = {
    DefaultHttpClient.get(it).bodyAsBytes()
}

suspend fun networkLoad(
    request : suspend (url: String) -> ByteArray,
    cacheStrategy: CacheStrategy = DiskCacheStrategy.Instance,
    url: String
): Pair<Path?, ByteArray?> {
    return withContext(Dispatchers.ioDispatcher) {
        try {
            try {
                cacheStrategy.load(url)?.let {
                    return@withContext cacheStrategy.path(url) to it
                }
            } catch (_: Throwable) {
            }

            val bytes = request(url)

            try {
                cacheStrategy.save(url, bytes)?.let {
                    return@withContext it to bytes
                }
            } catch (e: Throwable) {
                Timber.e("${this::class.simpleName} failed to cache downloaded asset")
            }
            null to bytes
        } catch (t: Throwable) {
            null to null
        }
    }
}